/*-------------------------------------------------------------------------
 *
 * predtest.c
 *	  尝试证明谓词表达式之间的逻辑蕴含的例程。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/optimizer/util/predtest.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/pathnodes.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"


/*
 * 涉及ScalarArrayOpExpr节点的大型数组的证明尝试
 * 可能需要O(N^2)时间，并且往往失败。
 * 因此，我们设置一个任意限制，允许我们
 * 将数组元素视为AND或OR子句。
 * XXX 值得将其暴露为GUC旋钮吗？
 */
#define MAX_SAOP_ARRAY_SIZE		100

/*
 * 为了避免在predicate_implied_by_recurse和
 * predicate_refuted_by_recurse中冗余编码，我们需要抽象出
 * 在逻辑上是AND或OR结构的表达式组件迭代的概念。
 * 有多种类型的表达式节点可以视为AND或OR，
 * 我们不想为每种类型单独编码。
 * 因此，这些类型和支持例程。
 */
typedef enum
{
	CLASS_ATOM,					/* 不是AND或OR的表达式 */
	CLASS_AND,					/* 具有AND语义的表达式 */
	CLASS_OR					/* 具有OR语义的表达式 */
} PredClass;

typedef struct PredIterInfoData *PredIterInfo;

typedef struct PredIterInfoData
{
	/* 节点类型特定的迭代状态 */
	void	   *state;
	List	   *state_list;
	/* 初始化以进行迭代 */
	void		(*startup_fn) (Node *clause, PredIterInfo info);
	/* 下一个组件的迭代函数 */
	Node	   *(*next_fn) (PredIterInfo info);
	/* 完成迭代后释放资源 */
	void		(*cleanup_fn) (PredIterInfo info);
} PredIterInfoData;

#define iterate_begin(item, clause, info)	\
	do { \
		Node   *item; \
		(info).startup_fn((clause), &(info)); \
		while ((item = (info).next_fn(&(info))) != NULL)

#define iterate_end(info)	\
		(info).cleanup_fn(&(info)); \
	} while (0)


static bool fc_predicate_implied_by_recurse(Node *fc_clause, Node *fc_predicate,
										 bool fc_weak);
static bool fc_predicate_refuted_by_recurse(Node *fc_clause, Node *fc_predicate,
										 bool fc_weak);
static PredClass fc_predicate_classify(Node *fc_clause, PredIterInfo fc_info);
static void fc_list_startup_fn(Node *fc_clause, PredIterInfo fc_info);
static Node *fc_list_next_fn(PredIterInfo fc_info);
static void fc_list_cleanup_fn(PredIterInfo fc_info);
static void fc_boolexpr_startup_fn(Node *fc_clause, PredIterInfo fc_info);
static void fc_arrayconst_startup_fn(Node *fc_clause, PredIterInfo fc_info);
static Node *fc_arrayconst_next_fn(PredIterInfo fc_info);
static void fc_arrayconst_cleanup_fn(PredIterInfo fc_info);
static void fc_arrayexpr_startup_fn(Node *fc_clause, PredIterInfo fc_info);
static Node *fc_arrayexpr_next_fn(PredIterInfo fc_info);
static void fc_arrayexpr_cleanup_fn(PredIterInfo fc_info);
static bool fc_predicate_implied_by_simple_clause(Expr *fc_predicate, Node *fc_clause,
											   bool fc_weak);
static bool fc_predicate_refuted_by_simple_clause(Expr *fc_predicate, Node *fc_clause,
											   bool fc_weak);
static Node *fc_extract_not_arg(Node *fc_clause);
static Node *fc_extract_strong_not_arg(Node *fc_clause);
static bool fc_clause_is_strict_for(Node *fc_clause, Node *fc_subexpr, bool fc_allow_false);
static bool fc_operator_predicate_proof(Expr *fc_predicate, Node *fc_clause,
									 bool fc_refute_it, bool fc_weak);
static bool fc_operator_same_subexprs_proof(Oid fc_pred_op, Oid fc_clause_op,
										 bool fc_refute_it);
static bool fc_operator_same_subexprs_lookup(Oid fc_pred_op, Oid fc_clause_op,
										  bool fc_refute_it);
static Oid	get_btree_test_op(Oid fc_pred_op, Oid fc_clause_op, bool fc_refute_it);
static void fc_InvalidateOprProofCacheCallBack(Datum fc_arg, int fc_cacheid, uint32 fc_hashvalue);



/*
 * predicate_implied_by
 *	  递归检查 clause_list 中的子句是否暗示给定的谓词为真。
 *
 * 我们支持两种蕴含的定义：
 *
 * "强" 蕴含：A 蕴含 B 意味着 A 的真值暗示 B 的真值。我们用这个来证明满足一个 WHERE 子句或索引谓词的行必须满足另一个。
 *
 * "弱" 蕴含：A 蕴含 B 意味着 A 的非虚假暗示 B 的非虚假（“非虚假”意味着“要么为真，要么为 NULL”）。我们用这个来证明满足一个 CHECK 约束的行必须满足另一个。
 *
 * 强蕴含也可以用来证明 WHERE 子句暗示 CHECK 约束，尽管在某些情况下它会失败，而我们可以安全地得出蕴含成立的结论。对于证明逆向情况没有支持，因为只有少数几种 CHECK 约束会允许推导出任何信息。
 *
 * 每个列表的顶层 List 结构对应于一个 AND 列表。我们假设 eval_const_expressions() 已经被应用，因此没有未展开的 AND 或 OR（例如，顶层 List 结构下方没有直接在 AND 内部的 AND）。
 * 如果这不成立，我们可能会无法证明有效的蕴含，但不会导致更糟糕的后果。
 *
 * 我们假设谓词已经检查过，仅包含不变的函数和运算符。（在许多当前的用法中，这被认为是正确的，因为谓词是通过了 CheckPredicate() 的索引谓词的一部分；否则，调用者必须检查它。）我们不敢基于非不变函数做出推论，因为它们可能在制定计划和执行计划之间更改答案。
 * 在这里，如果需要，将检查 clause_list 中的函数的不可变性。
 */
bool predicate_implied_by(List *fc_predicate_list, List *fc_clause_list,
					 bool fc_weak)
{
	Node	   *fc_p,
			   *fc_c;

	if (fc_predicate_list == NIL)
		return true;			/* 没有谓词：蕴含是无意义的 */
	if (fc_clause_list == NIL)
		return false;			/* 没有限制：蕴含必须失败 */

	/*
	 * 如果任一输入是单元素列表，则用它的唯一成员替换它；这避免了一层无用的 AND 递归。我们只需要在顶层担心这个，因为 eval_const_expressions 应该已经消除了下面任何微不足道的 AND 或 OR。
	 */
	if (list_length(fc_predicate_list) == 1)
		fc_p = (Node *) linitial(fc_predicate_list);
	else
		fc_p = (Node *) fc_predicate_list;
	if (list_length(fc_clause_list) == 1)
		fc_c = (Node *) linitial(fc_clause_list);
	else
		fc_c = (Node *) fc_clause_list;

	/* 并且我们开始了 ... */
	return fc_predicate_implied_by_recurse(fc_c, fc_p, fc_weak);
}

/*
 * predicate_refuted_by
 *	  递归检查 clause_list 中的子句是否反驳给定的
 *	  谓词（即，证明其为假）。
 *
 * 这与 !(predicate_implied_by) 不同，尽管在技术和代码结构上类似。
 *
 * 我们支持两种反驳的定义：
 *
 * “强”反驳：A 反驳 B 的意思是 A 的真值意味着 B 的假值。
 * 我们用此来证明给定 WHERE 子句的 CHECK 约束，即，
 * 证明任何满足 WHERE 子句的行将违反 CHECK
 * 约束。（请注意，我们必须证明 B 导致假，而不仅仅是非真。）
 *
 * “弱”反驳：A 反驳 B 的意思是 A 的真值意味着 B 的非真值
 * （即，B 必须导致假或 NULL）。我们用此来检测相互矛盾的 WHERE 子句。
 *
 * 在某些强反驳不成立的情况下，可以证明弱反驳，因此在可能的情况下使用它是有用的。
 * 目前我们尚未支持基于另一个 CHECK 反驳一个 CHECK 约束，
 * 也不支持基于 CHECK 反驳 WHERE。（与蕴含一样，最后一种情况
 * 似乎不太实用。CHECK 与 CHECK 之间的比较可能有用，但目前在任何地方都不需要。）
 *
 * 每个列表的顶层 List 结构对应于一个 AND 列表。
 * 我们假设 eval_const_expressions() 已经应用，因此
 * 不存在未展平的 AND 或 OR（例如，顶层 List 结构
 * 直接内嵌的 AND，没有 AND 紧接在其下）。
 * 如果这不成立，我们可能无法证明一个有效的蕴含，但不会产生更糟的后果。
 *
 * 我们假设谓词已经被检查为仅包含
 * 不变的函数和运算符。我们不敢根据
 * 不是不变的函数做推导，因为它们可能在
 * 我们制定计划和执行计划之间改变答案。
 * clause_list 中函数的不变性在此处进行检查。
 */
bool predicate_refuted_by(List *fc_predicate_list, List *fc_clause_list,
					 bool fc_weak)
{
	Node	   *fc_p,
			   *fc_c;

	if (fc_predicate_list == NIL)
		return false;			/* 没有谓词：反驳是不可能的 */
	if (fc_clause_list == NIL)
		return false;			/* 没有限制：反驳必须失败 */

	/*
	 * 如果任一输入是单元素列表，则用它的唯一成员替换它；这避免了一层无用的 AND 递归。我们只需要在顶层担心这个，因为 eval_const_expressions 应该已经消除了下面任何微不足道的 AND 或 OR。
	 */
	if (list_length(fc_predicate_list) == 1)
		fc_p = (Node *) linitial(fc_predicate_list);
	else
		fc_p = (Node *) fc_predicate_list;
	if (list_length(fc_clause_list) == 1)
		fc_c = (Node *) linitial(fc_clause_list);
	else
		fc_c = (Node *) fc_clause_list;

	/* 并且我们开始了 ... */
	return fc_predicate_refuted_by_recurse(fc_c, fc_p, fc_weak);
}

/*----------
 * predicate_implied_by_recurse
 *	  为非 NULL 限制和
 *	  谓词子句进行谓词蕴含测试。
 *
 * 此处遵循的逻辑是（“=>” 意味着 “蕴含”）：
 *	原子 A => 原子 B 当且仅当：		predicate_implied_by_simple_clause 这么说
 *	原子 A => AND-expr B 当且仅当：	A => B 的每一个组成部分
 *	原子 A => OR-expr B 当且仅当：	A => B 的任何组成部分
 *	AND-expr A => 原子 B 当且仅当：	A 的任何组成部分 => B
 *	AND-expr A => AND-expr B 当且仅当：A => B 的每一个组成部分
 *	AND-expr A => OR-expr B 当且仅当：A => B 的任何组成部分，
 *										*或者* A 的任何组成部分 => B
 *	OR-expr A => 原子 B 当且仅当：	A 的每一个组成部分 => B
 *	OR-expr A => AND-expr B 当且仅当：A => B 的每一个组成部分
 *	OR-expr A => OR-expr B 当且仅当：	A 的每一个组成部分 => B 的任何组成部分
 *
 * “原子”是指任何不是 AND 或 OR 节点的东西。请注意，我们没有
 * 特别的逻辑来处理 NOT 节点；这些应该在 eval_const_expressions() 
 * 期间被向下推送或消除。
 *
 * 所有这些规则同样适用于强或弱蕴含。
 *
 * 我们不能递归地先扩展任一侧，而必须根据上述规则交替扩展，
 * 以确保处理所有这些示例：
 *		(x OR y) => (x OR y OR z)
 *		(x AND y AND z) => (x AND y)
 *		(x AND y) => ((x AND y) OR z)
 *		((x OR y) AND z) => (x OR y)
 * 这仍然不是一项全面的测试，但在假设两个输入都已被 AND/OR 展平的情况下，它处理大多数正常情况。
 *
 * 我们必须准备好处理 restrictinfo 树中的 RestrictInfo 节点，
 * 尽管在谓词树中不处理。
 *----------
 */
static bool fc_predicate_implied_by_recurse(Node *fc_clause, Node *fc_predicate,
							 bool fc_weak)
{
	PredIterInfoData fc_clause_info;
	PredIterInfoData fc_pred_info;
	PredClass	fc_pclass;
	bool		fc_result;

	/* 跳过 RestrictInfo */
	Assert(fc_clause != NULL);
	if (IsA(fc_clause, RestrictInfo))
		fc_clause = (Node *) ((RestrictInfo *) fc_clause)->clause;

	fc_pclass = fc_predicate_classify(fc_predicate, &fc_pred_info);

	switch (fc_predicate_classify(fc_clause, &fc_clause_info))
	{
		case CLASS_AND:
			switch (fc_pclass)
			{
				case CLASS_AND:

					/*
					 * AND-clause => AND-clause 如果 A 蕴含 B 的每一个项
					 */
					fc_result = true;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (!fc_predicate_implied_by_recurse(fc_clause, fc_pitem,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_OR:

					/*
					 * AND-clause => OR-clause 如果 A 蕴含 B 的任何项
					 *
					 * 需要处理 (x AND y) => ((x AND y) OR z)
					 */
					fc_result = false;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (fc_predicate_implied_by_recurse(fc_clause, fc_pitem,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_pred_info);
					if (fc_result)
						return fc_result;

					/*
					 * 还要检查 A 的任何项是否蕴含 B
					 *
					 * 需要处理 ((x OR y) AND z) => (x OR y)
					 */
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						if (fc_predicate_implied_by_recurse(fc_citem, fc_predicate,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;

				case CLASS_ATOM:

					/*
					 * AND-clause => 原子 如果 A 的任何项蕴含 B
					 */
					fc_result = false;
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						if (fc_predicate_implied_by_recurse(fc_citem, fc_predicate,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;
			}
			break;

		case CLASS_OR:
			switch (fc_pclass)
			{
				case CLASS_OR:

					/*
					 * OR-clause => OR-clause 如果 A 的每一个项蕴含 B 的任何项。
					 * 杂乱但无法更简单地处理。
					 */
					fc_result = true;
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						bool		fc_presult = false;

						iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
						{
							if (fc_predicate_implied_by_recurse(fc_citem, fc_pitem,
															 fc_weak))
							{
								fc_presult = true;
								break;
							}
						}
						iterate_end(fc_pred_info);
						if (!fc_presult)
						{
							fc_result = false; /* 不蕴含 B 的任何项 */
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;

				case CLASS_AND:
				case CLASS_ATOM:

					/*
					 * OR-clause => AND-clause 如果 A 的每一个项蕴含 B
					 *
					 * OR-clause => 原子 如果 A 的每一个项蕴含 B
					 */
					fc_result = true;
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						if (!fc_predicate_implied_by_recurse(fc_citem, fc_predicate,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;
			}
			break;

		case CLASS_ATOM:
			switch (fc_pclass)
			{
				case CLASS_AND:

					/*
					 * 原子 => AND-clause 如果 A 蕴含 B 的每一个项
					 */
					fc_result = true;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (!fc_predicate_implied_by_recurse(fc_clause, fc_pitem,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_OR:

					/*
					 * 原子 => OR-clause 如果 A 蕴含 B 的任何项
					 */
					fc_result = false;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (fc_predicate_implied_by_recurse(fc_clause, fc_pitem,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_ATOM:

					/*
					 * 原子 => 原子 是基础情况
					 */
					return
						fc_predicate_implied_by_simple_clause((Expr *) fc_predicate,
														   fc_clause,
														   fc_weak);
			}
			break;
	}

	/* 不能到这里 */
	elog(ERROR, "predicate_classify returned a bogus value");
	return false;
}


/*----------
 * predicate_refuted_by_recurse
 *	  谓词否定测试，针对非NULL限制和
 *	  谓词子句。
 *
 * 这里遵循的逻辑是（"R=>" 表示 "否定"）：
 *	原子 A R=> 原子 B 当且仅当：		predicate_refuted_by_simple_clause 这样说
 *	原子 A R=> AND 表达式 B 当且仅当：	A R=> B 的任何组件
 *	原子 A R=> OR 表达式 B 当且仅当：	A R=> B 的每个组件
 *	AND 表达式 A R=> 原子 B 当且仅当：	A 的任何组件 R=> B
 *	AND 表达式 A R=> AND 表达式 B 当且仅当：	A R=> B 的任何组件，
 *									*或者* A 的任何组件 R=> B
 *	AND 表达式 A R=> OR 表达式 B 当且仅当：	A R=> B 的每个组件
 *	OR 表达式 A R=> 原子 B 当且仅当：	A 的每个组件 R=> B
 *	OR 表达式 A R=> AND 表达式 B 当且仅当：	A 的每个组件 R=> B 的任何组件
 *	OR 表达式 A R=> OR 表达式 B 当且仅当：	A R=> B 的每个组件
 *
 * 以上所有规则同样适用于强否定或弱否定。
 *
 * 此外，如果谓词是 NOT 子句，那么我们可以使用
 *	A R=> NOT B 如果：				A => B
 * 这适用于几个不同的 SQL 构造，它们声称其参数的非真实性，即 NOT、IS FALSE、IS NOT TRUE、IS UNKNOWN，尽管其中一些
 * 需要我们证明强蕴含。同样，我们可以使用
 *	NOT A R=> B 如果：				B => A
 * 但在这里我们必须小心强否定与弱否定，并进行适当类型的蕴含证明（分别为弱或强）。
 *
 * 其他注释与 predicate_implied_by_recurse() 相同。
 *----------
 */
static bool fc_predicate_refuted_by_recurse(Node *fc_clause, Node *fc_predicate,
							 bool fc_weak)
{
	PredIterInfoData fc_clause_info;
	PredIterInfoData fc_pred_info;
	PredClass	fc_pclass;
	Node	   *fc_not_arg;
	bool		fc_result;

	/* 跳过 RestrictInfo */
	Assert(fc_clause != NULL);
	if (IsA(fc_clause, RestrictInfo))
		fc_clause = (Node *) ((RestrictInfo *) fc_clause)->clause;

	fc_pclass = fc_predicate_classify(fc_predicate, &fc_pred_info);

	switch (fc_predicate_classify(fc_clause, &fc_clause_info))
	{
		case CLASS_AND:
			switch (fc_pclass)
			{
				case CLASS_AND:

					/*
					 * AND 子句 R=> AND 子句 如果 A 否定 B 的任何项
					 *
					 * 需要处理 (x AND y) R=> ((!x OR !y) AND z)
					 */
					fc_result = false;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (fc_predicate_refuted_by_recurse(fc_clause, fc_pitem,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_pred_info);
					if (fc_result)
						return fc_result;

					/*
					 * 还要检查 A 的任何项是否否定 B
					 *
					 * 需要处理 ((x OR y) AND z) R=> (!x AND !y)
					 */
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						if (fc_predicate_refuted_by_recurse(fc_citem, fc_predicate,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;

				case CLASS_OR:

					/*
					 * AND 子句 R=> OR 子句 如果 A 否定 B 的每个项
					 */
					fc_result = true;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (!fc_predicate_refuted_by_recurse(fc_clause, fc_pitem,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_ATOM:

					/*
					 * 如果 B 是 NOT 类型子句，A R=> B 如果 A => B 的参数
					 *
					 * 由于对于任何类型的否定，我们都以 A 为真的前提开始，
					 * 因此在所有情况下我们可以使用强蕴含测试。这证明了 B 的参数为真，
					 * 这对于弱否定来说已经足够，如果 B 是简单的 NOT，但这使得我们不必担心
					 * 我们拥有的确切否定子句的类型。
					 */
					fc_not_arg = fc_extract_not_arg(fc_predicate);
					if (fc_not_arg &&
						fc_predicate_implied_by_recurse(fc_clause, fc_not_arg,
													 false))
						return true;

					/*
					 * AND 子句 R=> 原子 如果 A 的任何项否定 B
					 */
					fc_result = false;
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						if (fc_predicate_refuted_by_recurse(fc_citem, fc_predicate,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;
			}
			break;

		case CLASS_OR:
			switch (fc_pclass)
			{
				case CLASS_OR:

					/*
					 * OR 子句 R=> OR 子句 如果 A 否定 B 的每个项
					 */
					fc_result = true;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (!fc_predicate_refuted_by_recurse(fc_clause, fc_pitem,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_AND:

					/*
					 * OR 子句 R=> AND 子句 如果 A 的每个项否定
					 * B 的任何项。
					 */
					fc_result = true;
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						bool		fc_presult = false;

						iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
						{
							if (fc_predicate_refuted_by_recurse(fc_citem, fc_pitem,
															 fc_weak))
							{
								fc_presult = true;
								break;
							}
						}
						iterate_end(fc_pred_info);
						if (!fc_presult)
						{
							fc_result = false; /* citem 不否定任何东西 */
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;

				case CLASS_ATOM:

					/*
					 * 如果 B 是 NOT 类型子句，A R=> B 如果 A => B 的参数
					 *
					 * 与上面 AND 子句的情况相同逻辑。
					 */
					fc_not_arg = fc_extract_not_arg(fc_predicate);
					if (fc_not_arg &&
						fc_predicate_implied_by_recurse(fc_clause, fc_not_arg,
													 false))
						return true;

					/*
					 * OR 子句 R=> 原子 如果 A 的每个项否定 B
					 */
					fc_result = true;
					iterate_begin(fc_citem, fc_clause, fc_clause_info)
					{
						if (!fc_predicate_refuted_by_recurse(fc_citem, fc_predicate,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_clause_info);
					return fc_result;
			}
			break;

		case CLASS_ATOM:

			/*
			 * 如果 A 是强 NOT 子句，A R=> B 如果 B => A 的参数
			 *
			 * 由于 A 是强的，我们可以假设 A 的参数为假（而不仅仅是
			 * 不为真）。如果 B 弱地蕴含 A 的参数，则 B 不能为
			 * 真或 NULL，因此证明了强否定。如果 B
			 * 强地蕴含 A 的参数，则 B 不能为真，因此证明了弱
			 * 否定。
			 */
			fc_not_arg = fc_extract_strong_not_arg(fc_clause);
			if (fc_not_arg &&
				fc_predicate_implied_by_recurse(fc_predicate, fc_not_arg,
											 !fc_weak))
				return true;

			switch (fc_pclass)
			{
				case CLASS_AND:

					/*
					 * 原子 R=> AND 子句 如果 A 否定 B 的任何项
					 */
					fc_result = false;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (fc_predicate_refuted_by_recurse(fc_clause, fc_pitem,
														 fc_weak))
						{
							fc_result = true;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_OR:

					/*
					 * 原子 R=> OR 子句 如果 A 否定 B 的每个项
					 */
					fc_result = true;
					iterate_begin(fc_pitem, fc_predicate, fc_pred_info)
					{
						if (!fc_predicate_refuted_by_recurse(fc_clause, fc_pitem,
														  fc_weak))
						{
							fc_result = false;
							break;
						}
					}
					iterate_end(fc_pred_info);
					return fc_result;

				case CLASS_ATOM:

					/*
					 * 如果 B 是 NOT 类型子句，A R=> B 如果 A => B 的参数
					 *
					 * 与上面 AND 子句的情况相同逻辑。
					 */
					fc_not_arg = fc_extract_not_arg(fc_predicate);
					if (fc_not_arg &&
						fc_predicate_implied_by_recurse(fc_clause, fc_not_arg,
													 false))
						return true;

					/*
					 * atom R=> atom 是基本情况
					 */
					return
						fc_predicate_refuted_by_simple_clause((Expr *) fc_predicate,
														   fc_clause,
														   fc_weak);
			}
			break;
	}

	/* 不能到这里 */
	elog(ERROR, "predicate_classify returned a bogus value");
	return false;
}


/*
 * predicate_classify
 *	  将表达式节点分类为 AND 类型、OR 类型或两者皆非（原子）。
 *
 * 如果表达式被分类为 AND 或 OR 类型，则 *info 将填写
 * 需要迭代其组件的函数。
 *
 * 此函数还实现了对 MAX_SAOP_ARRAY_SIZE 的强制执行：如果一个
 * ScalarArrayOpExpr 的数组元素过多，我们只将其分类为一个
 * 原子。  （这将导致其按原样传递给 simple_clause
 * 函数，其中许多将无法证明有关它的任何内容。）请注意，我们
 * 不能在考虑 MAX_SAOP_ARRAY_SIZE 元素后就停止；通常
 * 这会导致错误的证明，而不是无法证明任何内容。
 */
static PredClass
fc_predicate_classify(Node *fc_clause, PredIterInfo fc_info)
{
	/* 调用者不应传递 NULL，也不应传递 RestrictInfo 子句 */
	Assert(fc_clause != NULL);
	Assert(!IsA(fc_clause, RestrictInfo));

	/*
	 * 如果我们看到一个 List，假定它是一个隐式 AND 列表；这对于
	 * RestrictInfo 节点的列表是正确的语义。
	 */
	if (IsA(fc_clause, List))
	{
		fc_info->startup_fn = fc_list_startup_fn;
		fc_info->next_fn = fc_list_next_fn;
		fc_info->cleanup_fn = fc_list_cleanup_fn;
		return CLASS_AND;
	}

	/* 处理普通的 AND 和 OR 布尔子句 */
	if (is_andclause(fc_clause))
	{
		fc_info->startup_fn = fc_boolexpr_startup_fn;
		fc_info->next_fn = fc_list_next_fn;
		fc_info->cleanup_fn = fc_list_cleanup_fn;
		return CLASS_AND;
	}
	if (is_orclause(fc_clause))
	{
		fc_info->startup_fn = fc_boolexpr_startup_fn;
		fc_info->next_fn = fc_list_next_fn;
		fc_info->cleanup_fn = fc_list_cleanup_fn;
		return CLASS_OR;
	}

	/* 处理 ScalarArrayOpExpr */
	if (IsA(fc_clause, ScalarArrayOpExpr))
	{
		ScalarArrayOpExpr *fc_saop = (ScalarArrayOpExpr *) fc_clause;
		Node	   *fc_arraynode = (Node *) lsecond(fc_saop->args);

		/*
		 * 我们可以将其分解为 AND 或 OR 结构，但前提是我们
		 * 知道如何迭代数组元素中的表达式。
		 * 如果数组操作数是一个非空常量或一个简单的 ArrayExpr，
		 * 我们可以做到这一点。
		 */
		if (fc_arraynode && IsA(fc_arraynode, Const) &&
			!((Const *) fc_arraynode)->constisnull)
		{
			ArrayType  *fc_arrayval;
			int			fc_nelems;

			fc_arrayval = DatumGetArrayTypeP(((Const *) fc_arraynode)->constvalue);
			fc_nelems = ArrayGetNItems(ARR_NDIM(fc_arrayval), ARR_DIMS(fc_arrayval));
			if (fc_nelems <= MAX_SAOP_ARRAY_SIZE)
			{
				fc_info->startup_fn = fc_arrayconst_startup_fn;
				fc_info->next_fn = fc_arrayconst_next_fn;
				fc_info->cleanup_fn = fc_arrayconst_cleanup_fn;
				return fc_saop->useOr ? CLASS_OR : CLASS_AND;
			}
		}
		else if (fc_arraynode && IsA(fc_arraynode, ArrayExpr) &&
				 !((ArrayExpr *) fc_arraynode)->multidims &&
				 list_length(((ArrayExpr *) fc_arraynode)->elements) <= MAX_SAOP_ARRAY_SIZE)
		{
			fc_info->startup_fn = fc_arrayexpr_startup_fn;
			fc_info->next_fn = fc_arrayexpr_next_fn;
			fc_info->cleanup_fn = fc_arrayexpr_cleanup_fn;
			return fc_saop->useOr ? CLASS_OR : CLASS_AND;
		}
	}

	/* 以上都不适用，因此它是一个原子 */
	return CLASS_ATOM;
}

/*
 * PredIterInfo 例程用于迭代常规 List。 迭代
 * 状态变量是下一个要访问的 ListCell。
 */
static void fc_list_startup_fn(Node *fc_clause, PredIterInfo fc_info)
{
	fc_info->state_list = (List *) fc_clause;
	fc_info->state = (void *) list_head(fc_info->state_list);
}

static Node * fc_list_next_fn(PredIterInfo fc_info)
{
	ListCell   *fc_l = (ListCell *) fc_info->state;
	Node	   *fc_n;

	if (fc_l == NULL)
		return NULL;
	fc_n = lfirst(fc_l);
	fc_info->state = (void *) lnext(fc_info->state_list, fc_l);
	return fc_n;
}

static void fc_list_cleanup_fn(PredIterInfo fc_info)
{
	/* 没有需要清理的内容 */
}

/*
 * BoolExpr 需要其自己的启动函数，但可以使用 list_next_fn 和
 * list_cleanup_fn。
 */
static void fc_boolexpr_startup_fn(Node *fc_clause, PredIterInfo fc_info)
{
	fc_info->state_list = ((BoolExpr *) fc_clause)->args;
	fc_info->state = (void *) list_head(fc_info->state_list);
}

/*
 * PredIterInfo 例程用于迭代具有
 * 常量数组操作数的 ScalarArrayOpExpr。
 */
typedef struct
{
	OpExpr		opexpr;
	Const		constexpr;
	int			next_elem;
	int			num_elems;
	Datum	   *elem_values;
	bool	   *elem_nulls;
} ArrayConstIterState;

static void fc_arrayconst_startup_fn(Node *fc_clause, PredIterInfo fc_info)
{
	ScalarArrayOpExpr *fc_saop = (ScalarArrayOpExpr *) fc_clause;
	ArrayConstIterState *fc_state;
	Const	   *fc_arrayconst;
	ArrayType  *fc_arrayval;
	int16		fc_elmlen;
	bool		fc_elmbyval;
	char		fc_elmalign;

	/* 创建工作状态结构 */
	fc_state = (ArrayConstIterState *) palloc(sizeof(ArrayConstIterState));
	fc_info->state = (void *) fc_state;

	/* 解构数组字面量 */
	fc_arrayconst = (Const *) lsecond(fc_saop->args);
	fc_arrayval = DatumGetArrayTypeP(fc_arrayconst->constvalue);
	get_typlenbyvalalign(ARR_ELEMTYPE(fc_arrayval),
						 &fc_elmlen, &fc_elmbyval, &fc_elmalign);
	deconstruct_array(fc_arrayval,
					  ARR_ELEMTYPE(fc_arrayval),
					  fc_elmlen, fc_elmbyval, fc_elmalign,
					  &fc_state->elem_values, &fc_state->elem_nulls,
					  &fc_state->num_elems);

	/* 设置一个虚拟 OpExpr 作为每个项的节点返回 */
	fc_state->opexpr.xpr.type = T_OpExpr;
	fc_state->opexpr.opno = fc_saop->opno;
	fc_state->opexpr.opfuncid = fc_saop->opfuncid;
	fc_state->opexpr.opresulttype = BOOLOID;
	fc_state->opexpr.opretset = false;
	fc_state->opexpr.opcollid = InvalidOid;
	fc_state->opexpr.inputcollid = fc_saop->inputcollid;
	fc_state->opexpr.args = list_copy(fc_saop->args);

	/* 设置一个虚拟 Const 节点以保存每个元素的值 */
	fc_state->constexpr.xpr.type = T_Const;
	fc_state->constexpr.consttype = ARR_ELEMTYPE(fc_arrayval);
	fc_state->constexpr.consttypmod = -1;
	fc_state->constexpr.constcollid = fc_arrayconst->constcollid;
	fc_state->constexpr.constlen = fc_elmlen;
	fc_state->constexpr.constbyval = fc_elmbyval;
	lsecond(fc_state->opexpr.args) = &fc_state->constexpr;

	/* 初始化迭代状态 */
	fc_state->next_elem = 0;
}

static Node * fc_arrayconst_next_fn(PredIterInfo fc_info)
{
	ArrayConstIterState *fc_state = (ArrayConstIterState *) fc_info->state;

	if (fc_state->next_elem >= fc_state->num_elems)
		return NULL;
	fc_state->constexpr.constvalue = fc_state->elem_values[fc_state->next_elem];
	fc_state->constexpr.constisnull = fc_state->elem_nulls[fc_state->next_elem];
	fc_state->next_elem++;
	return (Node *) &(fc_state->opexpr);
}

static void fc_arrayconst_cleanup_fn(PredIterInfo fc_info)
{
	ArrayConstIterState *fc_state = (ArrayConstIterState *) fc_info->state;

	pfree(fc_state->elem_values);
	pfree(fc_state->elem_nulls);
	list_free(fc_state->opexpr.args);
	pfree(fc_state);
}

/*
 * PredIterInfo 例程用于迭代具有
 * 一维 ArrayExpr 数组操作数的 ScalarArrayOpExpr。
 */
typedef struct
{
	OpExpr		opexpr;
	ListCell   *next;
} ArrayExprIterState;

static void fc_arrayexpr_startup_fn(Node *fc_clause, PredIterInfo fc_info)
{
	ScalarArrayOpExpr *fc_saop = (ScalarArrayOpExpr *) fc_clause;
	ArrayExprIterState *fc_state;
	ArrayExpr  *fc_arrayexpr;

	/* 创建工作状态结构 */
	fc_state = (ArrayExprIterState *) palloc(sizeof(ArrayExprIterState));
	fc_info->state = (void *) fc_state;

	/* 设置一个虚拟 OpExpr 作为每个项的节点返回 */
	fc_state->opexpr.xpr.type = T_OpExpr;
	fc_state->opexpr.opno = fc_saop->opno;
	fc_state->opexpr.opfuncid = fc_saop->opfuncid;
	fc_state->opexpr.opresulttype = BOOLOID;
	fc_state->opexpr.opretset = false;
	fc_state->opexpr.opcollid = InvalidOid;
	fc_state->opexpr.inputcollid = fc_saop->inputcollid;
	fc_state->opexpr.args = list_copy(fc_saop->args);

	/* 将迭代变量初始化为 ArrayExpr 的第一个成员 */
	fc_arrayexpr = (ArrayExpr *) lsecond(fc_saop->args);
	fc_info->state_list = fc_arrayexpr->elements;
	fc_state->next = list_head(fc_arrayexpr->elements);
}

static Node * fc_arrayexpr_next_fn(PredIterInfo fc_info)
{
	ArrayExprIterState *fc_state = (ArrayExprIterState *) fc_info->state;

	if (fc_state->next == NULL)
		return NULL;
	lsecond(fc_state->opexpr.args) = lfirst(fc_state->next);
	fc_state->next = lnext(fc_info->state_list, fc_state->next);
	return (Node *) &(fc_state->opexpr);
}

static void fc_arrayexpr_cleanup_fn(PredIterInfo fc_info)
{
	ArrayExprIterState *fc_state = (ArrayExprIterState *) fc_info->state;

	list_free(fc_state->opexpr.args);
	pfree(fc_state);
}


/*----------
 * predicate_implied_by_simple_clause
 *	  对于“简单子句”谓词和“简单子句”限制，进行谓词蕴含性测试。
 *
 * 如果能够证明蕴含关系，则返回 true，否则返回 false。
 *
 * 我们有三种策略来确定一个简单子句是否蕴含另一个简单子句：
 *
 * 一种简单且通用的方法是查看它们是否相等；这适用于任何
 * 类型的表达式，并且适用于任何蕴含定义。 （实际上，
 * 假设表达式中的函数是不可变的——但这由调用者为谓词检查过。）
 *
 * 如果谓词的形式是“foo IS NOT NULL”，并且我们正在考虑
 * 强蕴含性，如果子句对“foo”是严格的，我们可以得出结论
 * 谓词是蕴含的，即当“foo”是 NULL 时它必须返回 false
 * 或 NULL。 在这种情况下，子句的真值确保“foo”不是 NULL。
 * （同样，这是一个安全的结论，因为“foo”必须是不可变的。）
 * 然而，这对于弱蕴含性不起作用。
 *
 * 最后，如果两个子句都是二元运算表达式，我们可能能够
 * 使用系统关于运算符的知识来证明某些东西；那些
 * 证明规则封装在 operator_predicate_proof() 中。
 *----------
 */
static bool fc_predicate_implied_by_simple_clause(Expr *fc_predicate, Node *fc_clause,
								   bool fc_weak)
{
	/* 允许中断长时间的证明尝试 */
	CHECK_FOR_INTERRUPTS();

	/* 首先尝试 equal() 测试 */
	if (equal((Node *) fc_predicate, fc_clause))
		return true;

	/* 接下来尝试 IS NOT NULL 情况 */
	if (!fc_weak &&
		fc_predicate && IsA(fc_predicate, NullTest))
	{
		NullTest   *fc_ntest = (NullTest *) fc_predicate;

		/* row IS NOT NULL 并不像我们想到的那样简单 */
		if (fc_ntest->nulltesttype == IS_NOT_NULL &&
			!fc_ntest->argisrow)
		{
			/* 对 foo 的子句的严格性意味着 foo IS NOT NULL */
			if (fc_clause_is_strict_for(fc_clause, (Node *) fc_ntest->arg, true))
				return true;
		}
		return false;			/* 我们无法成功... */
	}

	/* 否则尝试与运算符相关的知识 */
	return fc_operator_predicate_proof(fc_predicate, fc_clause, false, fc_weak);
}

/*----------
 * predicate_refuted_by_simple_clause
 *	  对于 "简单子句" 谓词和 "简单子句" 限制进行谓词反驳测试。
 *
 * 如果能够证明反驳，则返回 true，否则返回 false。
 *
 * 与蕴含情况不同，检查 equal() 子句没有帮助。
 * 但是 relation_excluded_by_constraints() 检查一组子句中的自我矛盾，
 * 因此我们可能会因为谓词和子句实际上是指针相等而到达这里，这值得快速消除。
 *
 * 当谓词的形式为 "foo IS NULL" 时，如果子句对 "foo" 是严格的（见蕴含案例的说明），
 * 或者是 "foo IS NOT NULL"，我们可以得出谓词被反驳的结论。
 * 对于强反驳或弱反驳都是有效的。
 *
 * 子句 "foo IS NULL" 在所有情况下反驳谓词 "foo IS NOT NULL"。
 * 如果我们考虑弱反驳，它还反驳一个对 "foo" 严格的谓词，
 * 因为此时谓词必须产生 false 或 NULL
 * （并且由于 "foo" 出现在谓词中，它是已知不可变的）。
 *
 * （覆盖这些 IS [NOT] NULL 情况的主要动机是支持
 * 使用 IS NULL/IS NOT NULL 作为分区定义约束。）
 *
 * 最后，如果两个子句都是二元运算符表达式，我们可能能够
 * 使用系统对运算符的知识证明某些内容；这些证明规则被封装在 operator_predicate_proof() 中。
 *----------
 */
static bool fc_predicate_refuted_by_simple_clause(Expr *fc_predicate, Node *fc_clause,
								   bool fc_weak)
{
	/* 允许中断长时间的证明尝试 */
	CHECK_FOR_INTERRUPTS();

	/* 一个简单子句不能反驳自身 */
	
/********** 值得检查，因为针对约束的关系排除（relation_excluded_by_constraints()） **********/
	if ((Node *) fc_predicate == fc_clause)
		return false;

	/* 尝试谓词-IS-NULL情况 */
	if (fc_predicate && IsA(fc_predicate, NullTest) &&
		((NullTest *) fc_predicate)->nulltesttype == IS_NULL)
	{
		Expr	   *fc_isnullarg = ((NullTest *) fc_predicate)->arg;

		/* 行为IS NULL并不是我们所想的简单方式 */
		if (((NullTest *) fc_predicate)->argisrow)
			return false;

		/* foo的严格性否定了foo IS NULL */
		if (fc_clause_is_strict_for(fc_clause, (Node *) fc_isnullarg, true))
			return true;

		/* foo IS NOT NULL否定了foo IS NULL */
		if (fc_clause && IsA(fc_clause, NullTest) &&
			((NullTest *) fc_clause)->nulltesttype == IS_NOT_NULL &&
			!((NullTest *) fc_clause)->argisrow &&
			equal(((NullTest *) fc_clause)->arg, fc_isnullarg))
			return true;

		return false;			/* 我们无法成功... */
	}

	/* 尝试子句-IS-NULL情况 */
	if (fc_clause && IsA(fc_clause, NullTest) &&
		((NullTest *) fc_clause)->nulltesttype == IS_NULL)
	{
		Expr	   *fc_isnullarg = ((NullTest *) fc_clause)->arg;

		/* 行为IS NULL并不是我们所想的简单方式 */
		if (((NullTest *) fc_clause)->argisrow)
			return false;

		/* foo IS NULL否定了foo IS NOT NULL */
		if (fc_predicate && IsA(fc_predicate, NullTest) &&
			((NullTest *) fc_predicate)->nulltesttype == IS_NOT_NULL &&
			!((NullTest *) fc_predicate)->argisrow &&
			equal(((NullTest *) fc_predicate)->arg, fc_isnullarg))
			return true;

		/* foo IS NULL弱否定任何对foo严格的谓词 */
		if (fc_weak &&
			fc_clause_is_strict_for((Node *) fc_predicate, (Node *) fc_isnullarg, true))
			return true;

		return false;			/* 我们无法成功... */
	}

	/* 否则尝试与运算符相关的知识 */
	return fc_operator_predicate_proof(fc_predicate, fc_clause, true, fc_weak);
}


/*
 * 如果子句声称一个子句的不真实，则返回该子句；
 * 否则返回NULL。
 */
static Node * fc_extract_not_arg(Node *fc_clause)
{
	if (fc_clause == NULL)
		return NULL;
	if (IsA(fc_clause, BoolExpr))
	{
		BoolExpr   *fc_bexpr = (BoolExpr *) fc_clause;

		if (fc_bexpr->boolop == NOT_EXPR)
			return (Node *) linitial(fc_bexpr->args);
	}
	else if (IsA(fc_clause, BooleanTest))
	{
		BooleanTest *fc_btest = (BooleanTest *) fc_clause;

		if (fc_btest->booltesttype == IS_NOT_TRUE ||
			fc_btest->booltesttype == IS_FALSE ||
			fc_btest->booltesttype == IS_UNKNOWN)
			return (Node *) fc_btest->arg;
	}
	return NULL;
}

/*
 * 如果子句声称一个子句的虚假，则返回该子句；
 * 否则返回NULL。
 */
static Node * fc_extract_strong_not_arg(Node *fc_clause)
{
	if (fc_clause == NULL)
		return NULL;
	if (IsA(fc_clause, BoolExpr))
	{
		BoolExpr   *fc_bexpr = (BoolExpr *) fc_clause;

		if (fc_bexpr->boolop == NOT_EXPR)
			return (Node *) linitial(fc_bexpr->args);
	}
	else if (IsA(fc_clause, BooleanTest))
	{
		BooleanTest *fc_btest = (BooleanTest *) fc_clause;

		if (fc_btest->booltesttype == IS_FALSE)
			return (Node *) fc_btest->arg;
	}
	return NULL;
}


/*
 * 如果假设“subexpr”将产生NULL，我们能否证明“clause”返回NULL（或FALSE）？
 *
 * 在计划程序的大多数地方，“严格性”指的是保证一个表达式对NULL输入会产生NULL输出，这也是
 * 我们在这里主要关注的。然而，在顶部级别的情况下，当已知子句会产生布尔值时，证明它不能在
 * “subexpr”为NULL时返回TRUE可能已经足够。当这个较弱的属性可以接受时，调用者应传递allow_false = true。
 * （当这个函数在内部递归时，我们传递allow_false = false，因为我们需要证明子表达式的实际NULL性。）
 *
 * 我们假设调用者检查过至少一个输入表达式是不可变的。此处的所有证明规则均涉及将“subexpr”匹配到
 * “clause”的某一部分，因此这允许假设“subexpr”是不可变的，而无需单独检查。
 *
 * 基本情况是clause和subexpr是equal()。
 *
 * 如果subexpr出现在“clause”的子表达式中，并且会迫使整体结果为NULL，我们也可以报告成功。
 */
static bool fc_clause_is_strict_for(Node *fc_clause, Node *fc_subexpr, bool fc_allow_false)
{
	ListCell   *fc_lc;

	/* 安全检查 */
	if (fc_clause == NULL || fc_subexpr == NULL)
		return false;

	/*
	 * 遍历任何RelabelType节点，以便我们可以匹配，例如，
	 * varcharcol与lower(varcharcol::text)。（一般来说，我们可以递归
	 * 通过任何保持NULL性、不可变的操作。）我们在这里不应该看到堆叠的RelabelTypes。
	 */
	if (IsA(fc_clause, RelabelType))
		fc_clause = (Node *) ((RelabelType *) fc_clause)->arg;
	if (IsA(fc_subexpr, RelabelType))
		fc_subexpr = (Node *) ((RelabelType *) fc_subexpr)->arg;

	/* 基本情况 */
	if (equal(fc_clause, fc_subexpr))
		return true;

	/*
	 * 如果我们有一个严格的操作符或函数，如果任何输入被subexpr强制为NULL，则保证结果为NULL。
	 * 即使操作符或函数不是不可变的，这也是可以的，因为它甚至不会在NULL输入上被调用。
	 */
	if (is_opclause(fc_clause) &&
		op_strict(((OpExpr *) fc_clause)->opno))
	{
		foreach(fc_lc, ((OpExpr *) fc_clause)->args)
		{
			if (fc_clause_is_strict_for((Node *) lfirst(fc_lc), fc_subexpr, false))
				return true;
		}
		return false;
	}
	if (is_funcclause(fc_clause) &&
		func_strict(((FuncExpr *) fc_clause)->funcid))
	{
		foreach(fc_lc, ((FuncExpr *) fc_clause)->args)
		{
			if (fc_clause_is_strict_for((Node *) lfirst(fc_lc), fc_subexpr, false))
				return true;
		}
		return false;
	}

	/*
	 * CoerceViaIO是严格的（无论它调用的I/O函数是否严格）。同样，ArrayCoerceExpr对其数组
	 * 参数是严格的（无论每个元素的表达式是什么），ConvertRowtypeExpr在行级别是严格的，CoerceToDomain也是严格的。
	 * 这些值得检查，主要是因为这可以让我们避免向用户解释为什么某些类型转换被认为是严格的而其他的不是。
	 */
	if (IsA(fc_clause, CoerceViaIO))
		return fc_clause_is_strict_for((Node *) ((CoerceViaIO *) fc_clause)->arg,
									fc_subexpr, false);
	if (IsA(fc_clause, ArrayCoerceExpr))
		return fc_clause_is_strict_for((Node *) ((ArrayCoerceExpr *) fc_clause)->arg,
									fc_subexpr, false);
	if (IsA(fc_clause, ConvertRowtypeExpr))
		return fc_clause_is_strict_for((Node *) ((ConvertRowtypeExpr *) fc_clause)->arg,
									fc_subexpr, false);
	if (IsA(fc_clause, CoerceToDomain))
		return fc_clause_is_strict_for((Node *) ((CoerceToDomain *) fc_clause)->arg,
									fc_subexpr, false);

	/*
	 * ScalarArrayOpExpr是一个特殊情况。注意，只有在我们未能将其解构为
	 * AND或OR树时，我们才会到达这里，例如，如果它具有太多数组元素。
	 */
	if (IsA(fc_clause, ScalarArrayOpExpr))
	{
		ScalarArrayOpExpr *fc_saop = (ScalarArrayOpExpr *) fc_clause;
		Node	   *fc_scalarnode = (Node *) linitial(fc_saop->args);
		Node	   *fc_arraynode = (Node *) lsecond(fc_saop->args);

		/*
		 * 如果我们能证明标量输入为null，并且操作符是严格的，则SAOP结果必须为null --- 除非数组是
		 * 空的。对于空数组，我们得到的要么是false（对于ANY），要么是true（对于ALL）。
		 * 如果allow_false = true则在ANY情况下证明无论如何都成功；否则，我们只能在能证明数组不为空的情况下进行证明。
		 */
		if (fc_clause_is_strict_for(fc_scalarnode, fc_subexpr, false) &&
			op_strict(fc_saop->opno))
		{
			int			fc_nelems = 0;

			if (fc_allow_false && fc_saop->useOr)
				return true;	/* 即使数组为空也可以成功 */

			if (fc_arraynode && IsA(fc_arraynode, Const))
			{
				Const	   *fc_arrayconst = (Const *) fc_arraynode;
				ArrayType  *fc_arrval;

				/*
				 * 如果数组是常量NULL，那么我们可以成功，如下面的情况所示。
				 */
				if (fc_arrayconst->constisnull)
					return true;

				/* 否则，我们可以计算元素的数量。 */
				fc_arrval = DatumGetArrayTypeP(fc_arrayconst->constvalue);
				fc_nelems = ArrayGetNItems(ARR_NDIM(fc_arrval), ARR_DIMS(fc_arrval));
			}
			else if (fc_arraynode && IsA(fc_arraynode, ArrayExpr) &&
					 !((ArrayExpr *) fc_arraynode)->multidims)
			{
				/*
				 * 如果输入是一个非多维的ARRAY[]表达式，我们也可以可靠地计算数组元素的数量。
				 */
				fc_nelems = list_length(((ArrayExpr *) fc_arraynode)->elements);
			}

			/* 如果数组肯定不为空，则证明成功 */
			if (fc_nelems > 0)
				return true;
		}

		/*
		 * 如果我们能证明数组输入为null，则在所有情况下证明成功，因为
		 * ScalarArrayOpExpr对于NULL数组将始终返回NULL。否则，我们在这里结束。
		 */
		return fc_clause_is_strict_for(fc_arraynode, fc_subexpr, false);
	}

	/*
	 * 当递归进入一个表达式时，我们可能会发现一个NULL常量。
	 * 无论它是否匹配subexpr，这肯定是NULL。
	 */
	if (IsA(fc_clause, Const))
		return ((Const *) fc_clause)->constisnull;

	return false;
}


/*
 * 定义“运算符蕴含表”以用于 btree 运算符（“策略”），
 * 并为驳斥定义类似表。
 *
 * btree 索引定义的策略数字（参见 access/stratnum.h）为：
 *		1 <		2 <=	3 =		4 >=	5 >
 * 此外，我们还使用 6 表示 <>。<> 不是一个可以在 btree 中索引的
 * 运算符，但我们假设在 btree opfamily 的等式运算符有一个否定运算符的情况下，
 * 否定运算符对 opfamily 的行为就像 <> 一样。
 * （这个约定在 get_op_btree_interpretation() 中也有说明。）
 *
 * BT_implies_table[] 和 BT_refutes_table[] 用于我们有两个相同的子表达式
 * 并且我们想知道一个运算符表达式是否蕴含或驳斥另一个的情况。
 * 也就是说，如果“子句”是 EXPR1 clause_op EXPR2，并且“谓词”是 EXPR1 pred_op EXPR2
 * 针对相同的两个（不可变）子表达式：
 *		BT_implies_table[clause_op-1][pred_op-1]
 *			如果子句蕴含谓词，则为真
 *		BT_refutes_table[clause_op-1][pred_op-1]
 *			如果子句驳斥谓词，则为真
 * 其中 clause_op 和 pred_op 是同一 btree opfamily 中的策略数字（从 1 到 6）。
 * 例如，“x < y”蕴含“x <= y”并驳斥“x > y”。
 *
 * BT_implic_table[] 和 BT_refute_table[] 用于我们需要比较的两个常量。
 * 以下是对：
 *
 *		test_op = BT_implic_table[clause_op-1][pred_op-1]
 *
 * 的解释，其中 test_op、clause_op 和 pred_op 是 btree 运算符的策略数字（从 1 到 6）：
 *
 *	 如果你知道，对于某个 EXPR，“EXPR clause_op CONST1”是真的，
 *	 而你想确定“EXPR pred_op CONST2”是否也必须是真的，
 *	 那么你可以用“CONST2 test_op CONST1”作为测试。
 *	 如果该测试返回真，则谓词表达式必须为真；如果测试返回假，则谓词表达式
 *	 可能为假。
 *
 * 例如，如果子句是“Quantity > 10”而谓词是“Quantity > 5”，
 * 那么我们测试“5 <= 10”，结果为真，所以子句蕴含谓词。
 *
 * 类似地，BT_refute_table 的条目解释如下：
 *
 *	 如果你知道，对于某个 EXPR，“EXPR clause_op CONST1”是真的，
 *	 而你想确定“EXPR pred_op CONST2”是否必须为假，
 *	 那么你可以用“CONST2 test_op CONST1”作为测试。
 *	 如果该测试返回真，则谓词表达式必须为假；
 *	 如果测试返回假，则谓词表达式可能为真。
 *
 * 例如，如果子句是“Quantity > 10”而谓词是“Quantity < 5”，
 * 那么我们测试“5 <= 10”，结果为真，所以子句驳斥谓词。
 *
 * 一个条目，其中 test_op == 0 表示无法确定蕴含。
 */

#define BTLT BTLessStrategyNumber
#define BTLE BTLessEqualStrategyNumber
#define BTEQ BTEqualStrategyNumber
#define BTGE BTGreaterEqualStrategyNumber
#define BTGT BTGreaterStrategyNumber
#define BTNE ROWCOMPARE_NE

/* 我们使用“none”表示 0/false，以使表格排列整齐 */
#define none 0

static const bool BT_implies_table[6][6] = {
/*
 *			谓词运算符：
 *	 LT    LE	 EQ    GE	 GT    NE
 */
	{true, true, none, none, none, true},	/* LT */
	{none, true, none, none, none, none},	/* LE */
	{none, true, true, true, none, none},	/* EQ */
	{none, none, none, true, none, none},	/* GE */
	{none, none, none, true, true, true},	/* GT */
	{none, none, none, none, none, true}	/* NE */
};

static const bool BT_refutes_table[6][6] = {
/*
 *			谓词运算符：
 *	 LT    LE	 EQ    GE	 GT    NE
 */
	{none, none, true, true, true, none},	/* LT */
	{none, none, none, none, true, none},	/* LE */
	{true, none, none, none, true, true},	/* EQ */
	{true, none, none, none, none, none},	/* GE */
	{true, true, true, none, none, none},	/* GT */
	{none, none, true, none, none, none}	/* NE */
};

static const StrategyNumber BT_implic_table[6][6] = {
/*
 *			谓词运算符：
 *	 LT    LE	 EQ    GE	 GT    NE
 */
	{BTGE, BTGE, none, none, none, BTGE},	/* LT */
	{BTGT, BTGE, none, none, none, BTGT},	/* LE */
	{BTGT, BTGE, BTEQ, BTLE, BTLT, BTNE},	/* EQ */
	{none, none, none, BTLE, BTLT, BTLT},	/* GE */
	{none, none, none, BTLE, BTLE, BTLE},	/* GT */
	{none, none, none, none, none, BTEQ}	/* NE */
};

static const StrategyNumber BT_refute_table[6][6] = {
/*
 *			谓词运算符：
 *	 LT    LE	 EQ    GE	 GT    NE
 */
	{none, none, BTGE, BTGE, BTGE, none},	/* LT */
	{none, none, BTGT, BTGT, BTGE, none},	/* LE */
	{BTLE, BTLT, BTNE, BTGT, BTGE, BTEQ},	/* EQ */
	{BTLE, BTLT, BTLT, none, none, none},	/* GE */
	{BTLE, BTLE, BTLE, none, none, none},	/* GT */
	{none, none, BTEQ, none, none, none}	/* NE */
};



/*
 * operator_predicate_proof
 *	  进行“简单子句”谓词的蕴含或反驳测试，并且“简单子句”限制，当两者都是
 *	  使用相关运算符和相同输入表达式的运算符子句时。
 *
 * 当 refute_it == false 时，我们想要证明谓词为真；
 * 当 refute_it == true 时，我们想要证明谓词为假。
 * （有足够的公共代码来证明在一个例程中处理这两种情况是合理的。）如果能够
 * 进行证明，则返回 true；如果无法证明，则返回 false。
 *
 * 我们在这里大多数情况下不需要区分强蕴含与弱蕴含/反驳。这取决于一个假设，
 * 相关运算符的对（即，
 * 交换子、否定子或 btree opfamily 兄弟）不会对相同输入返回一个 NULL 和一个非 NULL
 * 结果。因此，对于我们以子句的真实性假设开始的证明类型，谓词
 * 运算符也无法返回 NULL，因此无论我们是尝试进行强证明还是弱证明都无关紧要。
 * 对于弱蕴含，可能是子句运算符返回了 NULL，但然后谓词运算符
 * 也会这样，所以弱蕴含依然成立。这个论点不适用于考虑两个不同的常量值的情况，
 * 因为在那种情况下，运算符没有给出相同的输入。但我们只支持这对于 btree 运算符，
 * 我们可以假设所有非空输入都会产生非空输出，因此无论我们考虑哪两个非空常量都是无关的。
 * 如果任一常量为 NULL，则我们必须更加谨慎，但有时证明仍然有效，如下所述。
 *
 * 我们可以进行涉及几种表达形式的证明（这里 "foo" 和 "bar"
 * 代表根据 equal() 相等的子表达式）：
 *	"foo op1 bar" 如果 op1 是 op2 的否定子，则反驳 "foo op2 bar"
 *	"foo op1 bar" 如果 op1 是 op2 的交换子，则蕴含 "bar op2 foo"
 *	"foo op1 bar" 如果 op1 是 op2 的交换子的否定子，则反驳 "bar op2 foo"
 *	"foo op1 bar" 可以基于 btree 语义蕴含/反驳 "foo op2 bar"
 *	"foo op1 bar" 可以基于 btree 语义蕴含/反驳 "bar op2 foo"
 *	"foo op1 const1" 可以基于 btree 语义蕴含/反驳 "foo op2 const2"
 *
 * 在最后三种情况下，op1 和 op2 必须是同一 btree 运算符家族的成员。
 * 当两个子表达式相同时，想法是，例如，x < y 蕴含 x <= y，而
 * 不依赖于 x 和 y 的具体值。如果我们有两个不同的常量与相同的表达式
 * foo 进行比较，我们必须对两个常量值进行比较以确定结果；
 * 例如，foo < c1 蕴含 foo < c2 如果 c1 <= c2。我们假设在计划时
 * 比较常量是安全的，如果比较运算符是不可变的。
 *
 * 注意：所有运算符和子表达式必须是不可变的，以确保证明的安全性。
 * 我们假设谓词表达式完全不可变，因此在这里不需要对子表达式进行显式检查，
 * 但在某些情况下，我们需要额外检查运算符的不变性。特别是，
 * btree opfamilies 可以包含仅为稳定的跨类型运算符，我们不能使用那些进行推导。
 */
static bool fc_operator_predicate_proof(Expr *fc_predicate, Node *fc_clause,
						 bool fc_refute_it, bool fc_weak)
{
	OpExpr	   *fc_pred_opexpr,
			   *fc_clause_opexpr;
	Oid			fc_pred_collation,
				fc_clause_collation;
	Oid			fc_pred_op,
				fc_clause_op,
				fc_test_op;
	Node	   *fc_pred_leftop,
			   *fc_pred_rightop,
			   *fc_clause_leftop,
			   *fc_clause_rightop;
	Const	   *fc_pred_const,
			   *fc_clause_const;
	Expr	   *fc_test_expr;
	ExprState  *fc_test_exprstate;
	Datum		fc_test_result;
	bool		fc_isNull;
	EState	   *fc_estate;
	MemoryContext fc_oldcontext;

	/*
	 * 两个表达式必须是二元运算子子句，否则我们无法做任何事情。
	 *
	 * 注意：将来我们可能会将此逻辑扩展到其他基于运算符的
	 * 构造，例如 DistinctExpr。但在一般情况下，规划器对 DistinctExpr
	 * 不是很智能，这可能不是您想要改进的第一个地方。
	 */
	if (!is_opclause(fc_predicate))
		return false;
	fc_pred_opexpr = (OpExpr *) fc_predicate;
	if (list_length(fc_pred_opexpr->args) != 2)
		return false;
	if (!is_opclause(fc_clause))
		return false;
	fc_clause_opexpr = (OpExpr *) fc_clause;
	if (list_length(fc_clause_opexpr->args) != 2)
		return false;

	/*
	 * 如果它们被标记为不同的排序规则，那么我们无法做任何事情。
	 * 这是一个廉价的测试，所以我们尽早处理它。
	 */
	fc_pred_collation = fc_pred_opexpr->inputcollid;
	fc_clause_collation = fc_clause_opexpr->inputcollid;
	if (fc_pred_collation != fc_clause_collation)
		return false;

	/* 现在也抓取运算符 OIDs。我们可能在下面交换这些。 */
	fc_pred_op = fc_pred_opexpr->opno;
	fc_clause_op = fc_clause_opexpr->opno;

	/*
	 * 我们必须配对至少一对输入表达式。
	 */
	fc_pred_leftop = (Node *) linitial(fc_pred_opexpr->args);
	fc_pred_rightop = (Node *) lsecond(fc_pred_opexpr->args);
	fc_clause_leftop = (Node *) linitial(fc_clause_opexpr->args);
	fc_clause_rightop = (Node *) lsecond(fc_clause_opexpr->args);

	if (equal(fc_pred_leftop, fc_clause_leftop))
	{
		if (equal(fc_pred_rightop, fc_clause_rightop))
		{
			/* 我们有 x op1 y 和 x op2 y */
			return fc_operator_same_subexprs_proof(fc_pred_op, fc_clause_op, fc_refute_it);
		}
		else
		{
			/* 除非 rightops 都是 Consts，否则失败 */
			if (fc_pred_rightop == NULL || !IsA(fc_pred_rightop, Const))
				return false;
			fc_pred_const = (Const *) fc_pred_rightop;
			if (fc_clause_rightop == NULL || !IsA(fc_clause_rightop, Const))
				return false;
			fc_clause_const = (Const *) fc_clause_rightop;
		}
	}
	else if (equal(fc_pred_rightop, fc_clause_rightop))
	{
		/* 除非 leftops 都是 Consts，否则失败 */
		if (fc_pred_leftop == NULL || !IsA(fc_pred_leftop, Const))
			return false;
		fc_pred_const = (Const *) fc_pred_leftop;
		if (fc_clause_leftop == NULL || !IsA(fc_clause_leftop, Const))
			return false;
		fc_clause_const = (Const *) fc_clause_leftop;
		/* 交换两个运算符，以便我们可以假设 Consts 在右侧 */
		fc_pred_op = get_commutator(fc_pred_op);
		if (!OidIsValid(fc_pred_op))
			return false;
		fc_clause_op = get_commutator(fc_clause_op);
		if (!OidIsValid(fc_clause_op))
			return false;
	}
	else if (equal(fc_pred_leftop, fc_clause_rightop))
	{
		if (equal(fc_pred_rightop, fc_clause_leftop))
		{
			/* 我们有 x op1 y 和 y op2 x */
			/* 交换 pred_op，使我们可以将其视为直接匹配 */
			fc_pred_op = get_commutator(fc_pred_op);
			if (!OidIsValid(fc_pred_op))
				return false;
			return fc_operator_same_subexprs_proof(fc_pred_op, fc_clause_op, fc_refute_it);
		}
		else
		{
			/* 除非 pred_rightop/clause_leftop 都是 Consts，否则失败 */
			if (fc_pred_rightop == NULL || !IsA(fc_pred_rightop, Const))
				return false;
			fc_pred_const = (Const *) fc_pred_rightop;
			if (fc_clause_leftop == NULL || !IsA(fc_clause_leftop, Const))
				return false;
			fc_clause_const = (Const *) fc_clause_leftop;
			/* 交换 clause_op，以便我们可以假设 Consts 在右侧 */
			fc_clause_op = get_commutator(fc_clause_op);
			if (!OidIsValid(fc_clause_op))
				return false;
		}
	}
	else if (equal(fc_pred_rightop, fc_clause_leftop))
	{
		/* 除非 pred_leftop/clause_rightop 都是 Consts，否则失败 */
		if (fc_pred_leftop == NULL || !IsA(fc_pred_leftop, Const))
			return false;
		fc_pred_const = (Const *) fc_pred_leftop;
		if (fc_clause_rightop == NULL || !IsA(fc_clause_rightop, Const))
			return false;
		fc_clause_const = (Const *) fc_clause_rightop;
		/* 交换 pred_op，以便我们可以假设 Consts 在右侧 */
		fc_pred_op = get_commutator(fc_pred_op);
		if (!OidIsValid(fc_pred_op))
			return false;
	}
	else
	{
		/* 未能配对任何子表达式，因此我们失败 */
		return false;
	}

	/*
	 * 我们有两个相同的子表达式，以及两个不相同但都是 Consts 的
	 * 其他子表达式；如果有必要，我们已交换运算符，以便 Consts 在右侧。
	 * 我们需要比较 Consts 的值。如果其中一个是 NULL，我们无法
	 * 这样做，因此通常证明失败...但在某些情况下我们可以声称成功。
	 */
	if (fc_clause_const->constisnull)
	{
		/* 如果 clause_op 不是严格的，我们无法证明任何事情 */
		if (!op_strict(fc_clause_op))
			return false;

		/*
		 * 此时我们知道该条款返回 NULL。对于假设条款为真
		 * 的证明类型，这意味着证明在形式上是正确的（亦即“假命题可推出任何命题”）。
		 * 这适用于除了弱蕴涵的所有证明类型。
		 */
		if (!(fc_weak && !fc_refute_it))
			return true;

		/*
		 * 对于弱蕴涵，如果谓词也能证明为 NULL，证明仍有可能成功。
		 * 在这种情况下，我们有 NULL => NULL，对于这种证明类型是有效的。
		 */
		if (fc_pred_const->constisnull && op_strict(fc_pred_op))
			return true;
		/* 否则证明失败 */
		return false;
	}
	if (fc_pred_const->constisnull)
	{
		/*
		 * 如果 pred_op 是严格的，我们知道谓词的结果是 NULL，
		 * 这意味着证明对于弱蕴涵或弱反驳是成功的。
		 */
		if (fc_weak && op_strict(fc_pred_op))
			return true;
		/* 否则证明失败 */
		return false;
	}

	/*
	 * 使用系统目录和运算符蕴涵表查找常量比较运算符。
	 */
	fc_test_op = get_btree_test_op(fc_pred_op, fc_clause_op, fc_refute_it);

	if (!OidIsValid(fc_test_op))
	{
		/* 找不到合适的比较运算符 */
		return false;
	}

	/*
	 * 评估测试。为此我们需要一个 EState。
	 */
	fc_estate = CreateExecutorState();

	/* 我们可以使用状态机的工作上下文来避免内存泄漏。 */
	fc_oldcontext = MemoryContextSwitchTo(fc_estate->es_query_cxt);

	/* 构建表达式树 */
	fc_test_expr = make_opclause(fc_test_op,
							  BOOLOID,
							  false,
							  (Expr *) fc_pred_const,
							  (Expr *) fc_clause_const,
							  InvalidOid,
							  fc_pred_collation);

	/* 填充 opfuncids */
	fix_opfuncids((Node *) fc_test_expr);

	/* 为执行做好准备 */
	fc_test_exprstate = ExecInitExpr(fc_test_expr, NULL);

	/* 并执行它。 */
	fc_test_result = ExecEvalExprSwitchContext(fc_test_exprstate,
											GetPerTupleExprContext(fc_estate),
											&fc_isNull);

	/* 返回到外层内存上下文 */
	MemoryContextSwitchTo(fc_oldcontext);

	/* 释放我们刚创建的所有垃圾 */
	FreeExecutorState(fc_estate);

	if (fc_isNull)
	{
		/* 将 NULL 结果视为非证明……但这有点可疑…… */
		elog(DEBUG2, "null predicate test result");
		return false;
	}
	return DatumGetBool(fc_test_result);
}


/*
 * operator_same_subexprs_proof
 *	  假设 EXPR1 clause_op EXPR2 为真，尝试证明或反驳
 *	  EXPR1 pred_op EXPR2。
 *
 * 如果能够进行证明则返回 true，无法证明则返回 false。
 */
static bool fc_operator_same_subexprs_proof(Oid fc_pred_op, Oid fc_clause_op, bool fc_refute_it)
{
	/*
	 * 一个简单而通用的规则是，如果 clause_op 和 pred_op
	 * 相同，则谓词被证明；如果它们是彼此的否定，则被反驳。
	 * 我们不需要检查不变性，因为 pred_op 已知是不可变的。
	 * （实际上，到这一点为止，我们可能已经得到了已知不可变的
	 * pred_op 的对称运算符，但这当然也应该是不可变的。
	 * 同样，我们不担心 pred_op 的否定是否不可变。）
	 *
	 * 注意：“相同”情形不会在这里出现，如果我们确实有 EXPR1 clause_op
	 * EXPR2 和 EXPR1 pred_op EXPR2，因为在 predicate_implied_by_simple_clause
	 * 中的总体表达式相等测试会捕捉到它。但我们可以在交换
	 * pred_op 后看到相同的运算符。
	 */
	if (fc_refute_it)
	{
		if (get_negator(fc_pred_op) == fc_clause_op)
			return true;
	}
	else
	{
		if (fc_pred_op == fc_clause_op)
			return true;
	}

	/*
	 * 否则，看看我们是否可以通过找到运算符的关系来确定
	 * 通过某些 btree opfamily 。
	 */
	return fc_operator_same_subexprs_lookup(fc_pred_op, fc_clause_op, fc_refute_it);
}


/*
 * 我们使用一个旁路表来缓存 btree 证明运算符
 * 查找的结果，因为实际查找的开销相当大，并且对于给定的运算符对来说不会改变
 * （至少只要 pg_amop 不改变）。一个单一的哈希条目存储给定运算符对的
 * 含义和反驳结果；但请注意，我们可能只确定了其中一组结果。
 */
typedef struct OprProofCacheKey
{
	Oid			pred_op;		/* 谓词运算符 */
	Oid			clause_op;		/* 子句运算符 */
} OprProofCacheKey;

typedef struct OprProofCacheEntry
{
	/* 哈希查找键必须是第一个 */
	OprProofCacheKey key;

	bool		have_implic;	/* 我们知道含义结果吗？ */
	bool		have_refute;	/* 我们知道反驳结果吗？ */
	bool		same_subexprs_implies;	/* X clause_op Y 是否蕴含 X pred_op Y？ */
	bool		same_subexprs_refutes;	/* X clause_op Y 是否反驳 X pred_op Y？ */
	Oid			implic_test_op; /* 测试运算符的 OID，如果没有则为 0 */
	Oid			refute_test_op; /* 测试运算符的 OID，如果没有则为 0 */
} OprProofCacheEntry;

static HTAB *OprProofCacheHash = NULL;


/*
 * lookup_proof_cache
 *	  获取并在必要时填充适当的缓存条目。
 */
static OprProofCacheEntry *
fc_lookup_proof_cache(Oid fc_pred_op, Oid fc_clause_op, bool fc_refute_it)
{
	OprProofCacheKey fc_key;
	OprProofCacheEntry *fc_cache_entry;
	bool		fc_cfound;
	bool		fc_same_subexprs = false;
	Oid			fc_test_op = InvalidOid;
	bool		fc_found = false;
	List	   *fc_pred_op_infos,
			   *fc_clause_op_infos;
	ListCell   *fc_lcp,
			   *fc_lcc;

	/*
	 * 为这对运算符查找或创建一个缓存条目。
	 */
	if (OprProofCacheHash == NULL)
	{
		/* 第一次遍历：初始化哈希表 */
		HASHCTL		fc_ctl;

		fc_ctl.keysize = sizeof(OprProofCacheKey);
		fc_ctl.entrysize = sizeof(OprProofCacheEntry);
		OprProofCacheHash = hash_create("Btree proof lookup cache", 256,
										&fc_ctl, HASH_ELEM | HASH_BLOBS);

		/* 安排在 pg_amop 变化时刷新缓存 */
		CacheRegisterSyscacheCallback(AMOPOPID,
									  fc_InvalidateOprProofCacheCallBack,
									  (Datum) 0);
	}

	fc_key.pred_op = fc_pred_op;
	fc_key.clause_op = fc_clause_op;
	fc_cache_entry = (OprProofCacheEntry *) hash_search(OprProofCacheHash,
													 (void *) &fc_key,
													 HASH_ENTER, &fc_cfound);
	if (!fc_cfound)
	{
		/* 新的缓存条目，将其设置为无效 */
		fc_cache_entry->have_implic = false;
		fc_cache_entry->have_refute = false;
	}
	else
	{
		/* 现有的缓存条目，看看我们是否知道答案 */
		if (fc_refute_it ? fc_cache_entry->have_refute : fc_cache_entry->have_implic)
			return fc_cache_entry;
	}

	/*
	 * 尝试找到包含给定运算符的 btree opfamily。
	 *
	 * 我们必须找到一个包含两个运算符的 btree opfamily，否则
	 * 含义无法确定。此外，opfamily 必须包含一个合适的测试运算符，
	 * 该运算符接受运算符的右侧数据类型。
	 *
	 * 如果有多个匹配的 opfamilies，假设我们可以使用任意一个来
	 * 确定两个运算符的逻辑关系和正确的对应测试运算符。这应该适用于任何逻辑
	 * 一致的 opfamilies。
	 *
	 * 请注意，我们可以从缺乏可用测试的 opfamily 中
	 * 确定相同子表达式情况下运算符的关系。 这种情况可能发生在跨类型比较运算符集合不完整的情况下。
	 */
	fc_clause_op_infos = get_op_btree_interpretation(fc_clause_op);
	if (fc_clause_op_infos)
		fc_pred_op_infos = get_op_btree_interpretation(fc_pred_op);
	else						/* 没有必要寻找 */
		fc_pred_op_infos = NIL;

	foreach(fc_lcp, fc_pred_op_infos)
	{
		OpBtreeInterpretation *fc_pred_op_info = lfirst(fc_lcp);
		Oid			fc_opfamily_id = fc_pred_op_info->opfamily_id;

		foreach(fc_lcc, fc_clause_op_infos)
		{
			OpBtreeInterpretation *fc_clause_op_info = lfirst(fc_lcc);
			StrategyNumber fc_pred_strategy,
						fc_clause_strategy,
						fc_test_strategy;

			/* 必须在相同的 opfamily 中找到它们 */
			if (fc_opfamily_id != fc_clause_op_info->opfamily_id)
				continue;
			/* 左侧类型应匹配 */
			Assert(fc_clause_op_info->oplefttype == fc_pred_op_info->oplefttype);

			fc_pred_strategy = fc_pred_op_info->strategy;
			fc_clause_strategy = fc_clause_op_info->strategy;

			/*
			 * 检查我们是否可以基于运算符在这个 opfamily 中的关系
			 * 为相同子表达式情况做证据。
			 */
			if (fc_refute_it)
				fc_same_subexprs |= BT_refutes_table[fc_clause_strategy - 1][fc_pred_strategy - 1];
			else
				fc_same_subexprs |= BT_implies_table[fc_clause_strategy - 1][fc_pred_strategy - 1];

			/*
			 * 在含义表中查找“测试”策略编号
			 */
			if (fc_refute_it)
				fc_test_strategy = BT_refute_table[fc_clause_strategy - 1][fc_pred_strategy - 1];
			else
				fc_test_strategy = BT_implic_table[fc_clause_strategy - 1][fc_pred_strategy - 1];

			if (fc_test_strategy == 0)
			{
				/* 不能使用这种解释确定含义 */
				continue;
			}

			/*
			 * 查看 opfamily 是否拥有测试策略和数据类型的运算符。
			 */
			if (fc_test_strategy == BTNE)
			{
				fc_test_op = get_opfamily_member(fc_opfamily_id,
											  fc_pred_op_info->oprighttype,
											  fc_clause_op_info->oprighttype,
											  BTEqualStrategyNumber);
				if (OidIsValid(fc_test_op))
					fc_test_op = get_negator(fc_test_op);
			}
			else
			{
				fc_test_op = get_opfamily_member(fc_opfamily_id,
											  fc_pred_op_info->oprighttype,
											  fc_clause_op_info->oprighttype,
											  fc_test_strategy);
			}

			if (!OidIsValid(fc_test_op))
				continue;

			/*
			 * 最后检查：test_op 必须是不可变的。
			 *
			 * 请注意，我们只要求 test_op 是不可变的，而不是
			 * 原始的 clause_op。 （pred_op 假定已经被调用者检查为
			 * 不可变的。）基本上，我们假设 opfamily 是一致的，即使它包含
			 * 仅仅是稳定的运算符。
			 */
			if (op_volatile(fc_test_op) == PROVOLATILE_IMMUTABLE)
			{
				fc_found = true;
				break;
			}
		}

		if (fc_found)
			break;
	}

	list_free_deep(fc_pred_op_infos);
	list_free_deep(fc_clause_op_infos);

	if (!fc_found)
	{
		/* 找不到合适的比较运算符 */
		fc_test_op = InvalidOid;
	}

	/*
	 * 如果我们认为能够证明某些关于相同子表达式的情况
	 * ，在完全相信之前检查 clause_op 是否不可变。
	 * （通常，如果 pred_op 是不可变的，clause_op 也是不可变的，
	 * 但并不完全清楚这在所有情况下都必须成立，所以让我们检查一下。）
	 */
	if (fc_same_subexprs &&
		op_volatile(fc_clause_op) != PROVOLATILE_IMMUTABLE)
		fc_same_subexprs = false;

	/* 缓存结果，无论是正面还是负面 */
	if (fc_refute_it)
	{
		fc_cache_entry->refute_test_op = fc_test_op;
		fc_cache_entry->same_subexprs_refutes = fc_same_subexprs;
		fc_cache_entry->have_refute = true;
	}
	else
	{
		fc_cache_entry->implic_test_op = fc_test_op;
		fc_cache_entry->same_subexprs_implies = fc_same_subexprs;
		fc_cache_entry->have_implic = true;
	}

	return fc_cache_entry;
}

/*
 * operator_same_subexprs_lookup
 *	  便捷的子例程，用于查找相同子表达式情况的缓存答案。
 */
static bool fc_operator_same_subexprs_lookup(Oid fc_pred_op, Oid fc_clause_op, bool fc_refute_it)
{
	OprProofCacheEntry *fc_cache_entry;

	fc_cache_entry = fc_lookup_proof_cache(fc_pred_op, fc_clause_op, fc_refute_it);
	if (fc_refute_it)
		return fc_cache_entry->same_subexprs_refutes;
	else
		return fc_cache_entry->same_subexprs_implies;
}

/*
 * get_btree_test_op
 *	  确定用于 btree 运算符的比较运算符
 *	  证明或反驳涉及常量比较。
 *
 * 给定子句 "var clause_op const1" 的真实性，我们尝试证明或反驳
 * 谓词 "var pred_op const2"。两个运算符的身份足以确定比较
 * const2 和 const1 的运算符（如果有的话）。
 *
 * 返回要使用的运算符的 OID，如果没有可能的证明则返回 InvalidOid。
 */
static Oid get_btree_test_op(Oid fc_pred_op, Oid fc_clause_op, bool fc_refute_it)
{
	OprProofCacheEntry *fc_cache_entry;

	fc_cache_entry = fc_lookup_proof_cache(fc_pred_op, fc_clause_op, fc_refute_it);
	if (fc_refute_it)
		return fc_cache_entry->refute_test_op;
	else
		return fc_cache_entry->implic_test_op;
}


/*
 * pg_amop 无效事件的回调
 */
static void fc_InvalidateOprProofCacheCallBack(Datum fc_arg, int fc_cacheid, uint32 fc_hashvalue)
{
	HASH_SEQ_STATUS fc_status;
	OprProofCacheEntry *fc_hentry;

	Assert(OprProofCacheHash != NULL);

	/* 目前我们只是重置所有条目；很难更聪明... */
	hash_seq_init(&fc_status, OprProofCacheHash);

	while ((fc_hentry = (OprProofCacheEntry *) hash_seq_search(&fc_status)) != NULL)
	{
		fc_hentry->have_implic = false;
		fc_hentry->have_refute = false;
	}
}
